﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace MetadataBasedConfig.EntityModel.StaticConstraint
{
    public static class StaticConstraintHelper
    {
        #region Static Fields and Properties

        private static readonly Dictionary<string, object> StaticContraintPropertyValues = new Dictionary<string, object>();

        private static readonly Dictionary<Type, List<string>> TypeStaticConstraintPropertyDictionary = new Dictionary<Type, List<string>>();

        private static readonly List<Type> HasVerifiedTypes = new List<Type>();

        internal static bool IncludeStaticConstraint = true;

        #endregion

        #region

        private static void Verify<T>()
        {
            Type type = typeof(T);
            if (!HasVerifiedTypes.Contains(type))
            {
                List<string> allStaticProperties = new List<string>();
                PropertyInfo[] allPropertyInfos = type.GetProperties();
                foreach (PropertyInfo propertyInfo in allPropertyInfos)
                {
                    object[] objs = propertyInfo.GetCustomAttributes(typeof(StaticConstraintAttribute), false);
                    if (objs != null && objs.Length > 0)
                    {
                        allStaticProperties.Add(propertyInfo.Name);
                    }
                }
                if (allStaticProperties.Count > 0)
                {
                    if (TypeStaticConstraintPropertyDictionary.ContainsKey(type))
                        TypeStaticConstraintPropertyDictionary.Remove(type);
                    TypeStaticConstraintPropertyDictionary.Add(type, allStaticProperties);
                }
                HasVerifiedTypes.Add(type);
            }
        }

        internal static void EnsureVerify<T>()
        {
            if (!HasVerifiedTypes.Contains(typeof(T)))
            {
                Verify<T>();
            }
        }

        public static void SetStaticConstraintPropertyValue(string propertyName, object propertyValue)
        {
            if (StaticContraintPropertyValues.Keys.Contains(propertyName))
            {
                StaticContraintPropertyValues.Remove(propertyName);
            }
            StaticContraintPropertyValues.Add(propertyName, propertyValue);
        }

        public static object GetStaticConstraintPropertyValue(string propertyName)
        {
            return StaticContraintPropertyValues[propertyName];
        }

        public static void InitializeStaticConstraints(IEnumerable<KeyValuePair<string, object>> staticConstraintNameValueDict)
        {
            StaticContraintPropertyValues.Clear();
            foreach (KeyValuePair<string, object> propertyNameValue in staticConstraintNameValueDict)
            {
                if (!StaticContraintPropertyValues.Keys.Contains(propertyNameValue.Key))
                {
                    StaticContraintPropertyValues.Add(propertyNameValue.Key, propertyNameValue.Value);
                }
            }
        }

        public static List<string> GetStaticConstraintPropertyNames(Type type)
        {
            if (TypeStaticConstraintPropertyDictionary.ContainsKey(type))
                return TypeStaticConstraintPropertyDictionary[type];
            return new List<string>();
        }

        internal static string GenerateStaticConstraintParameterName(string propertyName)
        {
            return propertyName + Guid.NewGuid().ToString("N").Substring(0, 6);
        }
        #endregion
    }
}
